package steampunk.utils;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

public class CategoryTable<K, T> {

	private Hashtable<K, LinkedList<T>> lists = new Hashtable<K, LinkedList<T>>();
	
	
	private LinkedList<T> getLS(K cat, boolean make) {
		if (!lists.containsKey(cat)) {
			if (make) {
				LinkedList<T> ls = new LinkedList<T>();
				lists.put(cat, ls);
				return ls;
			}
			return null;
		}
		return lists.get(cat);
	}
	
	/**
	 * Returns the number of categories in this category table
	 * @return
	 */
	public int getCategoryCount() {
		return lists.size();
	}
	
	/**
	 * Returns an Iterable collection containing all of the
	 * categories in this table.
	 * @return
	 */
	public Iterable<K> getCategories() {
		return lists.keySet();
	}
	
	/**
	 * Adds the given item to the given category. This will
	 * not add duplicate entries to the same category, but
	 * the same item can be in more than one category.
	 * @param cat
	 * @param t
	 */
	public void add(K cat, T t) {
		List<T> ls = getLS(cat, true);
		if (!ls.contains(t))
			ls.add(t);
	}
	
	/**
	 * Removes the item from the category
	 * @param cat
	 * @param t
	 */
	public void remove(K cat, T t) {
		LinkedList<T> ls = getLS(cat, false);
		if (ls == null)
			return;
		ls.remove(t);
	}
	
	/**
	 * Removes all items from the specified category
	 * @param cat
	 */
	public void clear(K cat) {
		LinkedList<T> ls = getLS(cat, false);
		if (ls != null)
			ls.clear();
	}
	
	/**
	 * Removes all items in all categories
	 */
	public void clear() {
		Enumeration<K> cats = lists.keys();
		while (cats.hasMoreElements()) {
			lists.get(cats.nextElement()).clear();
		}
	}
	
	/**
	 * Returns the number of items in the category
	 * @param cat
	 * @return
	 */
	public int size(K cat) {
		LinkedList<T> ls = getLS(cat, false);
		if (ls == null) return 0;
		return ls.size();
	}
	
	/**
	 * Returns the internal List used to store that category. Changes
	 * to this list /will/ be reflected in the table, so be careful.
	 * @param cat
	 * @return
	 */
	public List<T> getCategoryList(K cat) {
		return getLS(cat, true);
	}
	
	/**
	 * Returns true if the given category contains the object.
	 * @param cat - the category
	 * @param e - the object
	 * @return
	 */
	public boolean contains(K cat, T e) {
		LinkedList<T> ls = getLS(cat, false);
		if (ls == null)
			return false;
		return ls.contains(e);
	}
}
